// locutor
// (c) 2009, Normen Müller, normen.mueller@gmail.com  
// $Id: RS.scala 86 2010-05-11 21:32:13Z normen.mueller $
package locutor.rws.rs

import java.io.File

import scaup.Views._

import locutor.rws.gm._
import locutor.rws.rs.parsing._

/**
 *  @author <a href="mailto:normen.mueller@googlemail.com">Normen M&#xFC;ller</a>
 *  @version 0.0.4
 */
abstract class Rule {
  val declaration: String
  
  override def toString = toGrGen
  
  def toGrGen = declaration
}

/**
 *  @author <a href="mailto:normen.mueller@googlemail.com">Normen M&#xFC;ller</a>
 *  @version 0.0.4
 */
case class RewriteRule(val name: String, val declaration: String) extends Rule

/**
 *  @author <a href="mailto:normen.mueller@googlemail.com">Normen M&#xFC;ller</a>
 *  @version 0.0.4
 */
case class TestRule(val name: String, val declaration: String) extends Rule

/**
 *  @author <a href="mailto:normen.mueller@googlemail.com">Normen M&#xFC;ller</a>
 *  @version 0.0.4
 */
case class Pattern(val name: Option[String], val declaration: String) extends Rule

/** Companion to <code>RuleSystem</code> class.
 * 
 *  @author <a href="mailto:normen.mueller@googlemail.com">Normen M&#xFC;ller</a>
 *  @version 0.0.4
 */                                                                      
object RuleSystem {
  private [rs] val REWRITE_RULES = System.getProperty("locutor.kb").toFile / "rws" / "rs"
  
  val empty = new RuleSystem(GraphModel.empty, Nil)  
  
  private [locutor] def parse(spec: File): RuleSystem =
    if(! ((REWRITE_RULES / spec.path) exists))
      error("Rule system \"" + (REWRITE_RULES / spec.path).path + "\" does not exist.")
    else parse((REWRITE_RULES / spec.path).content)
  
  private [rws] def parse(spec: String): RuleSystem =
    if(spec == null)
      error("Rule system may not be null.")
    else RuleSystemParser.parse(spec)  
}

/** A rule system.
 * 
 *  @author <a href="mailto:normen.mueller@googlemail.com">Normen M&#xFC;ller</a>
 *  @version 0.0.4
 */
class RuleSystem private [locutor] (val name: String, val graphModel: GraphModel, val rules: List[Rule]) {
  private [locutor] def this(name: String) = this(name, GraphModel.empty, Nil)
  
  private [locutor] def this(graphModel: GraphModel, rules: List[Rule]) = this("locutor", graphModel, rules)
  
  private [locutor] def withAnnotations = new RuleSystem(name, graphModel, annotationRules)
  
  //@todo bah! this has to be improved!
  private val annotationRules = {   
    RewriteRule(
      "annotate",
      "rule annotate { modify { exec(" + (((rules filter {case RewriteRule(name, _) if name startsWith "annotate_" => true case _ => false}) map {case RewriteRule(name, _) => name + "*"}) mkString " & ") + "); } }"
    ) ::
    RewriteRule(
      "interlink",
      "rule interlink { modify { exec(" + (((rules filter {case RewriteRule(name, _) if name startsWith "interlink_" => true case _ => false}) map {case RewriteRule(name, _) => name + "*"}) mkString " & ") + "); } }"
    ) ::
    rules
  }
  
  private [locutor] def withRippling = new RuleSystem(name, graphModel, ripplingRules)
  
  // @todo bah! this has to be improved!
  private val ripplingRules = {   
    RewriteRule(
      "ripple",
      "rule ripple { modify { exec(" + (((rules filter {case RewriteRule(name, _) if name startsWith "ripple_" => true case _ => false}) map {case RewriteRule(name, _) => name + "*"}) mkString " & ") + "); } }"
    ) ::
    rules
  }
  
  def join(these: List[RuleSystem]): RuleSystem = (this /: these)(_ join _)
  
  def join(that: RuleSystem): RuleSystem = new RuleSystem(name, graphModel join that.graphModel, ((rules.toSet /: that.rules)(_ + _)).toList)
    
  override def toString = toGrGen

  def toGrGen = (("using " + graphModel.name + ";\n") + ((rules map (_.toGrGen)) mkString "\n"))
}
